/* Copyright (C) 2016-2017 HangZhou Zenzet Technology Co., Ltd.
 * All right reserved

 * File:lktsqlparser.c
 * Author:guojianchuan
 * Date:2017-05-19

 */

/* 系统头文件 */
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <setjmp.h>
#include <stdarg.h>

/* GSP_PARSER头文件 */
#include "linked_list.h"
#include "cstring.h" 
#include "gsp_base.h"
#include "gsp_node.h"
#include "gsp_list.h"
#include "gsp_sourcetoken.h"
#include "gsp_sqlparser.h"

/* 本模块头文件 */
#include "lktsqlparser.h"
#include "lkterr.h"

#define CHARACTER_SPACE                         ' '
#define CHARACTER_DOT                           '.'
#define CHARACTER_BACK_QUOTE                    '`'
#define LOG_MAX_LEN                             256
#define IDENTIFY_COLUMN_MAX_NUM                 256 
#define IDENTIFY_TABLE_MAX_NUM                  64
#define MYSQL_IDENTIFIEY_MAX_LEN                64
#define DATABASE_NAME_MAX_LEN                   MYSQL_IDENTIFIEY_MAX_LEN
#define DATABASE_ALIS_NAME_MAX_LEN              MYSQL_IDENTIFIEY_MAX_LEN
#define TABLE_NAME_MAX_LEN                      MYSQL_IDENTIFIEY_MAX_LEN
#define TABLE_ALIAS_NAME_MAX_LEN                MYSQL_IDENTIFIEY_MAX_LEN
#define COLUMN_NAME_MAX_LEN                     MYSQL_IDENTIFIEY_MAX_LEN

#define CHECK_STRING_VALUE(expr)\
        ((((eet_simple_constant == expr->expressionType) &&\
        (NULL != expr->constantOperand) &&\
        (ect_string == expr->constantOperand->constantType) &&\
        (_LKT_SQLPARSER_Get_GspNodeText_Len((gsp_node*)expr->constantOperand)) > 2)) ? 1 : 0)
#define CHECK_SIMPLEOBJECT_VALUE(expr)\
            (((eet_simple_object_name == expr->expressionType) &&\
            (NULL != expr->objectOperand) &&\
            (edb_unknown == expr->objectOperand->objectType)) ? 1 : 0)      
#define CHECK_SIMPLEOBJECT_PARENTHESIS(expr)\
            (((eet_parenthesis == expr->expressionType) &&\
            (NULL != expr->leftOperand)) ? 1 : 0) 
            
#define _LKT_PRINT_LOG(errCode, log)   _LKT_SQLPARSER_PrintLog(__FILE__, __LINE__, errCode, log)
#define _LKT_SQLPARSER_ParseWhereCondition _LKT_SQLPARSER_ParseExpression

typedef struct tagSQLParserWorker
{
    SQLPARSER_STATEMENT_S *parseStatement;
    SQLPARSER_COLUMN_NODE_S **current;
    logger logFunc;
}SQLPARSER_WORKER_S;

typedef struct tagTableName
{
    char dbName[DATABASE_NAME_MAX_LEN];
    char tableName[TABLE_NAME_MAX_LEN];
    char tableAlias[TABLE_ALIAS_NAME_MAX_LEN];
}TABLE_NAME_S;

typedef struct tagTableIdentify
{
    int tableNum;
    TABLE_NAME_S tableNode[IDENTIFY_TABLE_MAX_NUM];
}TABLE_IDENTIFY_S;

typedef enum tagIdentifyType
{
    IDENTIFY_TABLE = 0,
    IDENTIFY_COLUMN = 1
}IDENTIFY_TYPE_E;

static SQLPARSER_WORKER_S gsqlParserWorker;
static const char* gsql = NULL;

static int _LKT_SQLPARSER_Get_GspNodeText_Len(gsp_node *node)
{
    char *tmp = gsp_node_text(node);
    size_t len = strlen(tmp);
    gsp_free(tmp);
    return (int)len;
}

static SQLPARSER_WORKER_S* _LKT_SQLPARSER_GetParserWorker(void)
{
    return &gsqlParserWorker;
}

static void _LKT_SQLPARSER_PrintLog (const char* file, int line, int errCode, const char* log)
{
    SQLPARSER_WORKER_S *worker = _LKT_SQLPARSER_GetParserWorker();
    
    logger logFunc = worker->logFunc;

    char formatLog[LOG_MAX_LEN] = {0};
    snprintf (formatLog, sizeof (formatLog), "[errcode:%d] [%s-%d] %s", errCode, file, errCode, log);
    
    if (NULL == logFunc)
    {
        fprintf(stderr, formatLog);
    }
    else
    {
        logFunc (formatLog);
    }
    
    return;
}

static int _LKT_IsStringValue (char* value)
{
    int bString = 0;

    if ((NULL == value) || (0 == strlen(value)) || (strlen(value) <= 2))
    {
        /* 等于2的意思表示，value只等于空值 '' */
        return bString;
    }

    int len = strlen(value);
    char sigleQuote = '\'';
    char doubleQuote = '"';

    if ((sigleQuote == value[0]) && (sigleQuote == value[len - 1]))
    {
        bString = 1;
    }
    else if ((doubleQuote == value[0]) && (doubleQuote == value[len - 1]))
    {
        bString = 1;
    }

    return bString;
}

static void _LKT_SQLPARSER_SplitIdentify 
(
    const char *identify, 
    char *dbName,
    char *tblName,
    char *columnName,
    int identifyType
)
{
    //TODO 需要增加字符串检测接口
    if ((NULL == identify) || (NULL == dbName) || (NULL == tblName))
    {
        return;
    }
    
    int identiyLen = strlen(identify);
    int i = 0;
    int j = 0;
    int k = 0;
    int prevDot = 0;
    int backquoteNum = 0;
    char section[3][MYSQL_IDENTIFIEY_MAX_LEN] = {0};
    memset (section, 0, sizeof (section));

    /* 分割db, table, column */
    for (i = 0; i < identiyLen; i++)
    {
        if (CHARACTER_DOT == identify[i])
        {
            backquoteNum = 0;
            for (j = 0; j < i; j++)
            {
                if (CHARACTER_BACK_QUOTE == identify[j])
                {
                    backquoteNum++;
                }
            }

            if (0 == backquoteNum % 2)
            {
                if (0 == k)
                {
                    strncpy (section[k++], &identify[prevDot], i);
                }
                else
                {
                    strncpy (section[k++], &identify[prevDot + 1], i - prevDot - 1);
                }
                prevDot = i;
            }

        }
    }

    if (0 == k)
    {
        strncpy (section[k++], &identify[prevDot], i);
    }
    else
    {
        strncpy (section[k++], &identify[prevDot + 1], i - prevDot - 1);
    }
    //printf ("|%s|%s|%s|\n", section[0], section[1], section[2]);
    
    /* 去除首尾空格 */
    int sectionNum = sizeof (section) / sizeof (section[0]);
    int sectionLen = 0;
    int start      = 0;
    int end        = 0;
    int copyLen    = 0;
    char tmpBuffer[MYSQL_IDENTIFIEY_MAX_LEN] = {0};
    for (i = 0; i < sectionNum; i++)
    {
        sectionLen = strlen (section[i]);
        
        for (j = 0; j < sectionLen; j++)
        {
            if (CHARACTER_SPACE != section[i][j])
            {
                start = j;
                break;
            }
        }
        for (j = sectionLen - 1; j >= 0; j--)
        {
            if (CHARACTER_SPACE != section[i][j])
            {
                end = j;
                break;
            }
        }
        
        /* 检查单字符的标识符 */
        if ((start == end) && (0 != start))
        {
            copyLen = 1;
            strncpy (tmpBuffer, &section[i][start], copyLen);
            tmpBuffer[copyLen] = '\0';
            snprintf (section[i], MYSQL_IDENTIFIEY_MAX_LEN, "%s", tmpBuffer);
        }
        else
        {            
            copyLen = end - start + 1;
            strncpy (tmpBuffer, &section[i][start], copyLen);
            tmpBuffer[copyLen] = '\0';
            snprintf (section[i], MYSQL_IDENTIFIEY_MAX_LEN, "%s", tmpBuffer);
        }
    }

    /* 去除首尾反引号 */
    start      = 0;
    end        = 0;
    copyLen    = 0;
    memset (tmpBuffer, 0, sizeof (tmpBuffer));
    for (i = 0; i < sectionNum; i++)
    {
        sectionLen = strlen (section[i]);
        
        for (j = 0; j < sectionLen; j++)
        {
            if (CHARACTER_BACK_QUOTE != section[i][j])
            {
                start = j;
                break;
            }
        }
        for (j = sectionLen - 1; j >= 0; j--)
        {
            if (CHARACTER_BACK_QUOTE != section[i][j])
            {
                end = j;
                break;
            }
        }
        
        /* 检查单字符的标识符 */
        if ((start == end) && (0 != start))
        {
            copyLen = 1;
            strncpy (tmpBuffer, &section[i][start], copyLen);
            tmpBuffer[copyLen] = '\0';
            snprintf (section[i], MYSQL_IDENTIFIEY_MAX_LEN, "%s", tmpBuffer);
        }
        else
        {            
            copyLen = end - start + 1;
            strncpy (tmpBuffer, &section[i][start], copyLen);
            tmpBuffer[copyLen] = '\0';
            snprintf (section[i], MYSQL_IDENTIFIEY_MAX_LEN, "%s", tmpBuffer);
        }
    }

    if (IDENTIFY_TABLE == identifyType)
    {
        if (1 == k)
        {
            /* 标识符内包含table */
            snprintf (tblName, MYSQL_IDENTIFIEY_MAX_LEN, "%s", section[0]);
        }
        else if (2 == k)
        {
            /* 标识符内包含db, table */
            snprintf (dbName, MYSQL_IDENTIFIEY_MAX_LEN, "%s", section[0]);
            snprintf (tblName, MYSQL_IDENTIFIEY_MAX_LEN, "%s", section[1]);
        }
    }
    else if (IDENTIFY_COLUMN == identifyType)
    {
        if (1 == k)
        {
            /* 标识符内包含column */
            if (NULL != columnName)
            {
                snprintf (columnName, MYSQL_IDENTIFIEY_MAX_LEN, "%s", section[0]);
            }
        }
        else if (2 == k)
        {
            /* 标识符内包含table, column */
            snprintf (tblName, MYSQL_IDENTIFIEY_MAX_LEN, "%s", section[0]);
            if (NULL != columnName)
            {
                snprintf (columnName, MYSQL_IDENTIFIEY_MAX_LEN, "%s", section[1]);
            }
        }
        else if (3 == k)
        {
            /* 标识符内包含db, table, column */
            snprintf (dbName, MYSQL_IDENTIFIEY_MAX_LEN, "%s", section[0]);
            snprintf (tblName, MYSQL_IDENTIFIEY_MAX_LEN, "%s", section[1]);
            if (NULL != columnName)
            {
                snprintf (columnName, MYSQL_IDENTIFIEY_MAX_LEN, "%s", section[2]);
            }
        }
    }
    
    return;
}

static char* _LKT_SQLPARSER_CopyString (const char* src, int len)
{
    if (NULL == src)
    {
        return NULL;
    }

    char *p = (char*) malloc (len + 1);
    if (NULL == p)
    {
        return NULL;
    }
    memcpy (p, src, len);
    p[len] = '\0';

    return p;
}

static SQLPARSER_COLUMN_NODE_S* _LKT_SQLPARSER_FreeNode (SQLPARSER_COLUMN_NODE_S *node)
{
    if (NULL == node)
    {
        return NULL;
    }

    if (NULL != node->value)
    {
        free (node->value); 
        node->value = NULL;
    }

    if (NULL != node->column)
    {
        free (node->column); 
        node->column = NULL;
    }
    
    if (NULL != node->prefixTable)
    {
        free (node->prefixTable); 
        node->prefixTable = NULL;
    }

    int i = 0;
    for (i = 0; i < node->possbileTable.tableNum; i++)
    {
        free (node->possbileTable.tableNode[i].dbName);
        free (node->possbileTable.tableNode[i].tableName);
        node->possbileTable.tableNode[i].dbName = NULL;
        node->possbileTable.tableNode[i].tableName = NULL;
    }
    node->possbileTable.tableNum = 0;
    
    if (NULL != node->prefixDatabase)
    {
        free (node->prefixDatabase); 
        node->prefixDatabase = NULL;
    }

    SQLPARSER_COLUMN_NODE_S *next = node->next;

    free (node);

    return  next;
}

static void _LKT_FREE_Statement (SQLPARSER_STATEMENT_S * pstatement)
{
    if (NULL == pstatement)
    {
        return;
    }

    if (NULL != pstatement->originsql)
    {
        free (pstatement->originsql);
        pstatement->originsql = NULL;
    }

    SQLPARSER_COLUMN_NODE_S *node = pstatement->header;
    while (NULL != node)
    {
        node = _LKT_SQLPARSER_FreeNode(node);
    }

    free (pstatement);

    return;
}

static char* _LKT_SQLPARSER_AddOriginSQL (const char* sql)
{
    if (NULL == sql)
    {
        return NULL;
    }
    
    SQLPARSER_WORKER_S *worker = _LKT_SQLPARSER_GetParserWorker();

    if ((NULL != sql) && (0 != strlen(sql)))
    {
        worker->parseStatement->originsql = _LKT_SQLPARSER_CopyString (sql, strlen(sql));
    }
    
    return worker->parseStatement->originsql;
}

static void _LKT_SQLPARSER_AddOStatementType (int stmtType)
{
    SQLPARSER_WORKER_S *worker = _LKT_SQLPARSER_GetParserWorker();
    
    switch(stmtType)
    {
        case sstselect:
        {
            worker->parseStatement->stmtType = state_select;
            break;
        }
        case sstdelete:
        {
            worker->parseStatement->stmtType = state_delete;
            break;
        }
        case sstinsert:
        {
            worker->parseStatement->stmtType = state_insert;
            break;
        }
        case sstupdate:
        {
            worker->parseStatement->stmtType = state_update;
            break;
        }
        default:
        {
            worker->parseStatement->stmtType = state_invalid;
            break;
        }
    }

    return;
}

static void _LKT_SQLPARSER_SetNodeMatchPattern (gsp_expr* expr,SQLPARSER_COLUMN_NODE_S *node)
{
    if ((NULL == expr) || (NULL == node))
    {
        return;
    }

    if (eet_pattern_matching == expr->expressionType)
    {
        node->isMatchPattern = 1;

        /* 检查是否是Like匹配还是其他匹配 */
        char *pattern = expr->operatorToken->pStr;
        if (NULL != pattern)
        {
            if (0 == strncmp ("like", pattern, strlen("like")))
            {
                node->matchPattern.matchType = LIKE;
            }
            else
            {
                node->matchPattern.matchType = OTHERS;
            }
        }

        /* 检查匹配前面是否有Not 关键词 */
        if (NULL != expr->notToken)
        {
            node->matchPattern.isHaveNotToken = 1;
        }
        else
        {
            node->matchPattern.isHaveNotToken = 0;
        }

        /* 检查匹配的转义字符 */
        if ((NULL != expr->likeEscapeOperand) && 
            ((NULL != expr->likeEscapeOperand->constantOperand) ||
            (NULL != expr->likeEscapeOperand->objectOperand)))
        {
            char* escapeString  =  NULL;
            if (NULL != expr->likeEscapeOperand->constantOperand)
            {
                escapeString = gsp_node_text((gsp_node*)expr->likeEscapeOperand->constantOperand);
            }
            else if (NULL != expr->likeEscapeOperand->objectOperand)
            {
                escapeString = gsp_node_text((gsp_node*)expr->likeEscapeOperand->objectOperand);
            }
            if ((NULL != escapeString) && (strlen (escapeString) == 3))
            {
                node->matchPattern.isHaveEscapeChar = 1;
                node->matchPattern.escapeChar = escapeString[1];
            }
            else
            {
                node->matchPattern.isHaveEscapeChar = 0;
                node->matchPattern.escapeChar = 0;
            }
            gsp_free(escapeString);
        }
    }

    return;
}

static SQLPARSER_COLUMN_NODE_S*  _LKT_SQLPARSER_AddNode 
(
    char *value, 
    char *column, 
    char *table, 
    char *database, 
    TABLE_IDENTIFY_S *tableIdentify, 
    int offset, 
    int len, 
    int idx
)
{
    if ((NULL == value) || (0 == strlen(value)) || (strlen(value) <= 2))
    {
        /* 等于2的意思表示，value只等于空值 '' */
        return;
    }
    
    SQLPARSER_WORKER_S *worker = _LKT_SQLPARSER_GetParserWorker();
    if (NULL == worker->parseStatement->header)
    {
        worker->current = (SQLPARSER_COLUMN_NODE_S**)&(worker->parseStatement->header);
    }

    int ret = ERR_COMMON_SUCCESS;
    SQLPARSER_COLUMN_NODE_S* node = NULL;
    SQLPARSER_COLUMN_NODE_S* retNode = NULL;
    do
    {
        node = (SQLPARSER_COLUMN_NODE_S*) malloc (sizeof (SQLPARSER_COLUMN_NODE_S));
        if (NULL == node)
        {
            break;
        }
        memset (node, 0, sizeof (SQLPARSER_COLUMN_NODE_S));

        /* 填充value值, +1，-2表示去除首尾的单引号 */
        node->value = _LKT_SQLPARSER_CopyString (value + 1, len - 2);
        
        /* 填充offset, len, idex */
        node->len = len - 2;
        node->offset = offset;
        node->idx = idx;

        /* 填充column值 */
        if ((NULL != column) && (0 != strlen(column)))
        {
            node->column = _LKT_SQLPARSER_CopyString (column, strlen(column));
        }

        /* 填充table值 */
        if ((NULL != table) && (0 != strlen(table)))
        {
            node->prefixTable = _LKT_SQLPARSER_CopyString (table, strlen(table));
        }

        /* 填充tableList值 */
        if (NULL != tableIdentify)
        {
            int i = 0;
            for (i = 0; i < tableIdentify->tableNum; i++)
            {
                node->possbileTable.tableNode[i].tableName = _LKT_SQLPARSER_CopyString(tableIdentify->tableNode[i].tableName,
                                                                                       strlen(tableIdentify->tableNode[i].tableName));
                node->possbileTable.tableNode[i].dbName    = _LKT_SQLPARSER_CopyString(tableIdentify->tableNode[i].dbName,
                                                             strlen(tableIdentify->tableNode[i].dbName));
            }
            node->possbileTable.tableNum = tableIdentify->tableNum;
        }


        /* 填充db值*/
        if ((NULL != database) && (0 != strlen(database)))
        {
            node->prefixDatabase = _LKT_SQLPARSER_CopyString (database, strlen(database));
        }


        worker->parseStatement->nodeNum++;
    } while (0);

    /* value, table必须要有 */
    if (NULL == node->value)
    {
        fprintf (stderr, "no memory\n");
        _LKT_SQLPARSER_FreeNode (node);
        return NULL;
    }

    retNode = node;
    *worker->current = node;
    node->next = NULL;

    worker->current = &node->next;
    
    return retNode;
}

static void _LKT_SQLPARSER_AssociateNode
(
    char **pptableName,
    char **ppdbName,
    char *tblPrefixName,
    char *dbPrefixName,
    TABLE_IDENTIFY_S *tableIdentify
)
{
    int ret = ERR_COMMON_SUCCESS;
    
    if ((NULL == pptableName) ||
       (NULL == ppdbName) ||
       (NULL == tblPrefixName) || 
       (NULL == dbPrefixName) ||
       (NULL == tableIdentify))
    {
        ret = ERR_COMMON_INVALID_PARAM;
        _LKT_PRINT_LOG (ret, "invalid param");
        return;
    }

    if (0 != strlen(dbPrefixName))
    {
        *ppdbName    = dbPrefixName;
        *pptableName = tblPrefixName;
        /* 下面这种格式，解析暂时不支持，用的应该会比较少 */
        //delete from runoob.runoob_tbl using runoob.runoob_tbl inner join runoob.zenzet_tbl as ppp 
        //where runoob_tbl.runoob_id=4 and runoob.ppp.runoob_id =5; 第二个ppp关联为第一个ppp
    }
    else if (0 != strlen(tblPrefixName))
    {
        *pptableName = tblPrefixName;

        /* 如果column解析出来前面有table,不能直接拿来使用，因为有可能是alias，需要再进一步确定 */
        int i = 0;
        for (i = 0; i < tableIdentify->tableNum; i++)
        {
           if ((0 == strncmp (tblPrefixName, tableIdentify->tableNode[i].tableAlias, sizeof (tblPrefixName))) ||
               (0 == strncmp (tblPrefixName, tableIdentify->tableNode[i].tableName, sizeof (tblPrefixName))))
           {
               *pptableName = tableIdentify->tableNode[i].tableName;
               *ppdbName    = tableIdentify->tableNode[i].dbName;
               break;
           }
        }
    }

    return;
}

/****************************************************************/
static void _LKT_SQLPARSER_AnalyzeSelect( gsp_selectStatement * psql );
static void _LKT_SQLPARSER_AnalyzeUpdate( gsp_updateStatement * psql );
static void _LKT_SQLPARSER_AnalyzeDelete( gsp_deleteStatement * psql );

static void _LKT_SQLPARSER_ParseSubQuery (gsp_selectSqlNode *subQuery)
{
    if (NULL == subQuery)
    {
        return;
    }

    if (t_gsp_selectStatement == subQuery->nodeType)
    {
        _LKT_SQLPARSER_AnalyzeSelect(subQuery);
    }

    return;
}

static void _LKT_SQLPARSER_ParseTableReferences (gsp_fromTable *join, TABLE_IDENTIFY_S *tableIdentify)
{
    if ((NULL == join) || (NULL == tableIdentify))
    {
        return;
    }

    int tableNum = tableIdentify->tableNum;
    
    if (NULL != join->tableName)
    {
        char *tmpGspNodeText = gsp_node_text((gsp_node*)join->tableName);
        _LKT_SQLPARSER_SplitIdentify (tmpGspNodeText, 
                                      tableIdentify->tableNode[tableNum].dbName,
                                      tableIdentify->tableNode[tableNum].tableName,
                                      NULL,
                                      IDENTIFY_TABLE);
        gsp_free(tmpGspNodeText);
        if (join->aliasClause != NULL)
        {
            tmpGspNodeText = gsp_node_text((gsp_node*)join->aliasClause);
            snprintf (tableIdentify->tableNode[tableNum].tableAlias, 
                      TABLE_ALIAS_NAME_MAX_LEN, 
                      "%s", 
                      tmpGspNodeText);
            gsp_free(tmpGspNodeText);
        }
        tableNum++;
        tableIdentify->tableNum = tableNum;
    }
    else if (NULL != join->joinExpr)
    {
        if (NULL != join->joinExpr->leftOperand)
        {
            _LKT_SQLPARSER_ParseTableReferences (join->joinExpr->leftOperand, tableIdentify);
        }
        
        if (NULL != join->joinExpr->rightOperand)
        {
            _LKT_SQLPARSER_ParseTableReferences (join->joinExpr->rightOperand, tableIdentify);
        }
    }

    
    return;
}

static void  _LKT_SQLPARSER_ParseExpression (gsp_expr* expr, TABLE_IDENTIFY_S *tableIdentify)
{
    if ((NULL == expr) || (NULL == tableIdentify))
    {
        return;
    }
    
    EExpressionType retExprType   = eet_not_initialized_yet;
    EExpressionType leftExprType  = eet_not_initialized_yet;
    EExpressionType rightExprType = eet_not_initialized_yet;
    
    gsp_expr* leftOperand = expr->leftOperand;
    gsp_expr* rightOperand = expr->rightOperand;
    if ((NULL != leftOperand) && (NULL != rightOperand))
    {
        char *identify = NULL;
        char *myvalue  = NULL;
        char *mycolumn = NULL;
        char *mytable  = NULL;
        char *mydb     = NULL;
        int offset     = NULL;
        int len        = 0;
        int idx        = -1;
        char dbPrefixName[DATABASE_NAME_MAX_LEN]     = {0};
        char tblPrefixName[TABLE_NAME_MAX_LEN]    = {0};
        char columnName[COLUMN_NAME_MAX_LEN] = {0};

        if ((CHECK_SIMPLEOBJECT_VALUE(leftOperand)) && (CHECK_STRING_VALUE(rightOperand)))
        {
            identify = gsp_node_text((gsp_node*)leftOperand->objectOperand);
            myvalue  = gsp_node_text((gsp_node*)rightOperand->constantOperand);
            offset = ((gsp_node*)rightOperand->constantOperand)->fragment.startToken->nColumn;
            len = strlen(myvalue);
           
            _LKT_SQLPARSER_SplitIdentify(identify, dbPrefixName, tblPrefixName, columnName, IDENTIFY_COLUMN);
            
            _LKT_SQLPARSER_AssociateNode(&mytable, &mydb, tblPrefixName, dbPrefixName, tableIdentify);            

            mycolumn = columnName;
            
            SQLPARSER_COLUMN_NODE_S *node = _LKT_SQLPARSER_AddNode (myvalue, mycolumn, mytable, 
                                                                     mydb, tableIdentify,offset, len, idx);
            if (NULL != node)
            {
                _LKT_SQLPARSER_SetNodeMatchPattern (expr, node);
            }

            gsp_free(identify);
            gsp_free(myvalue);
        }
        else if ((CHECK_SIMPLEOBJECT_VALUE(rightOperand)) && (CHECK_STRING_VALUE(leftOperand)))
        {
            myvalue  = gsp_node_text((gsp_node*)leftOperand->constantOperand);
            identify = gsp_node_text((gsp_node*)rightOperand->objectOperand);
            offset = ((gsp_node*)leftOperand->constantOperand)->fragment.startToken->nColumn;
            len = strlen(myvalue);
            
            _LKT_SQLPARSER_SplitIdentify(identify, dbPrefixName, tblPrefixName, columnName, IDENTIFY_COLUMN);
            
            _LKT_SQLPARSER_AssociateNode(&mytable, &mydb, tblPrefixName, dbPrefixName, tableIdentify);
            
            mycolumn = columnName;

            SQLPARSER_COLUMN_NODE_S *node = _LKT_SQLPARSER_AddNode (myvalue, mycolumn, mytable, 
                                                 mydb, tableIdentify,offset, len, idx);
            if (NULL != node)
            {
                _LKT_SQLPARSER_SetNodeMatchPattern (expr, node);
            }
            
            gsp_free(identify);
            gsp_free(myvalue);
        }
        else if ((CHECK_SIMPLEOBJECT_VALUE(rightOperand)) && (CHECK_SIMPLEOBJECT_VALUE(leftOperand)))
        {
            char *tmpvalue1 = gsp_node_text((gsp_node*)leftOperand->objectOperand);
            char *tmpvalue2  = gsp_node_text((gsp_node*)rightOperand->objectOperand);
            if (1 == _LKT_IsStringValue (tmpvalue1))
            {
                identify = gsp_node_text((gsp_node*)rightOperand->objectOperand);
                offset = ((gsp_node*)leftOperand)->fragment.startToken->nColumn;
                myvalue = tmpvalue1;
            }
            else if (1 == _LKT_IsStringValue (tmpvalue2))
            {
                identify = gsp_node_text((gsp_node*)leftOperand->objectOperand);
                offset = ((gsp_node*)rightOperand)->fragment.startToken->nColumn;
                myvalue = tmpvalue2;
            }
            else
            {
                gsp_free(identify);
                gsp_free(tmpvalue1);
                gsp_free(tmpvalue2);
                return;
            }

            len = strlen(myvalue);
            
            _LKT_SQLPARSER_SplitIdentify(identify, dbPrefixName, tblPrefixName, columnName, IDENTIFY_COLUMN);
            
            _LKT_SQLPARSER_AssociateNode(&mytable, &mydb, tblPrefixName, dbPrefixName, tableIdentify);
            
            mycolumn = columnName;

            SQLPARSER_COLUMN_NODE_S *node = _LKT_SQLPARSER_AddNode (myvalue, mycolumn, mytable, 
                                                 mydb, tableIdentify,offset, len, idx);
            if (NULL != node)
            {
                _LKT_SQLPARSER_SetNodeMatchPattern (expr, node);
            }
            
            gsp_free(identify);
            gsp_free(tmpvalue1);
            gsp_free(tmpvalue2);
        }
        else
        {
            (void) _LKT_SQLPARSER_ParseExpression (leftOperand, tableIdentify);
                
            (void) _LKT_SQLPARSER_ParseExpression (rightOperand, tableIdentify);
        }
    }
    else if (CHECK_SIMPLEOBJECT_PARENTHESIS (expr))
    {
        (void) _LKT_SQLPARSER_ParseExpression (leftOperand, tableIdentify);
    }
    else if (NULL != expr->subQueryNode)
    {
        _LKT_SQLPARSER_ParseSubQuery (expr->subQueryNode);
    }

    return;
}

static void _LKT_SQLPARSER_SelectStmtInfo (gsp_selectStatement * sqlStmt) 
{    
    if (NULL == sqlStmt)
    {
        return;
    }
    
    gsp_listcell *cell;

    switch (sqlStmt->setOperator)
    {
        case eso_none:
        {
            break;
        }
        case eso_union:
        {
            _LKT_SQLPARSER_SelectStmtInfo(sqlStmt->leftStmt);
            _LKT_SQLPARSER_SelectStmtInfo(sqlStmt->rightStmt);
            break;
        }
        case eso_unionall:
        {
            _LKT_SQLPARSER_SelectStmtInfo(sqlStmt->leftStmt);
            _LKT_SQLPARSER_SelectStmtInfo(sqlStmt->rightStmt);
            break;
        }
        default:
        {
            return;
        }
    }

    if (eso_none != sqlStmt->setOperator)
    {
        //TODO:
    }
    else
    {
        int i = 0;
        TABLE_IDENTIFY_S tableIdentify;
        memset (&tableIdentify, 0, sizeof (tableIdentify));
        
        /* 获取table */
        if(NULL != sqlStmt->fromTableList)
        {
            foreach(cell, sqlStmt->fromTableList)
            {
                gsp_fromTable *join = (gsp_fromTable *)gsp_list_celldata(cell);
                _LKT_SQLPARSER_ParseTableReferences(join, &tableIdentify);
            }
        }
        
        if(sqlStmt->whereCondition!=NULL)
        {
            _LKT_SQLPARSER_ParseWhereCondition (sqlStmt->whereCondition->condition, &tableIdentify);
        }        
    }

    return;
}

static void _LKT_SQLPARSER_AnalyzeSelect( gsp_selectStatement * psql ) 
{
    _LKT_SQLPARSER_SelectStmtInfo(psql);
    
    return;
}

static void _LKT_SQLPARSER_DeleteStmtInfo( gsp_deleteStatement * sqlStmt ) 
{
    if (NULL == sqlStmt)
    {
        return;
    }
    
    TABLE_IDENTIFY_S tableIdentify;
    memset (&tableIdentify, 0, sizeof (tableIdentify));
    
    int tableNum = 0;

    /* single table. eg: "delete from tbl1 where name = 'zenzet'" */
    if (NULL != sqlStmt->targetTableNode)
    {
        gsp_fromTable *fromTable = sqlStmt->targetTableNode;            
        char *tmpGspNodeText = gsp_node_text((gsp_node*)fromTable);
        _LKT_SQLPARSER_SplitIdentify (tmpGspNodeText, 
                                      tableIdentify.tableNode[tableNum].dbName,
                                      tableIdentify.tableNode[tableNum].tableName,
                                      NULL,
                                      IDENTIFY_TABLE);
        gsp_free(tmpGspNodeText);
        tableNum++;
        tableIdentify.tableNum = tableNum;
        /* mysql语法仅支持multiple-table的情况下设置alias ,所以这里不需要判断 */
    }
    
    if (NULL != sqlStmt->sourceTableList)
    {
        gsp_listcell *cell = NULL;
        foreach(cell, sqlStmt->sourceTableList)
        {
            gsp_fromTable *join = (gsp_fromTable *)gsp_list_celldata(cell);            
            _LKT_SQLPARSER_ParseTableReferences(join, &tableIdentify);
        }
    }

    if(NULL != sqlStmt->whereCondition)
    {
        _LKT_SQLPARSER_ParseWhereCondition(sqlStmt->whereCondition->condition, &tableIdentify);
    }

    return;
}

static void _LKT_SQLPARSER_AnalyzeDelete( gsp_deleteStatement * psql ) 
{
    _LKT_SQLPARSER_DeleteStmtInfo(psql);
    
    return;
}

static void _LKT_SQLPARSER_InsertStmtInfo( gsp_insertStatement * sqlStmt ) 
{
    int ret = ERR_COMMON_SUCCESS;
    char dbPrefixName[DATABASE_NAME_MAX_LEN]     = {0};
    char tblPrefixName[TABLE_NAME_MAX_LEN]       = {0};
    char columnName[COLUMN_NAME_MAX_LEN]         = {0};
    char *tmpGspNodeText = NULL; 
    /* 获取Table名称 */
    char tableName[TABLE_NAME_MAX_LEN] = {0};
    if(sqlStmt->targetTableNode!=NULL)
    {
        tmpGspNodeText = gsp_node_text((gsp_node*)sqlStmt->targetTableNode);
        /* insert语句，在table和column同时有db,tbl前缀的时候，MySQL以table的前缀为主 */
        _LKT_SQLPARSER_SplitIdentify(tmpGspNodeText, 
                                     dbPrefixName, tblPrefixName, columnName, IDENTIFY_TABLE);
        gsp_free(tmpGspNodeText);
        snprintf (tableName, sizeof (tableName), "%s", tblPrefixName);
    }

    /* 获取Column */
    int i = 0;
    gsp_listcell *cell = NULL;

    if(sqlStmt->columnList!=NULL && sqlStmt->columnList->length>IDENTIFY_COLUMN_MAX_NUM)
    {
        return;
    }

    char *columnList[IDENTIFY_COLUMN_MAX_NUM];
    memset (columnList, 0, sizeof (columnList));

    if(sqlStmt->columnList!=NULL && sqlStmt->columnList->length>0)
    {
        foreach(cell, sqlStmt->columnList)
        {
            char dbTmpPrefixName[DATABASE_NAME_MAX_LEN]     = {0};
            char tblTmpPrefixName[TABLE_NAME_MAX_LEN]       = {0};
            memset (dbTmpPrefixName, 0, sizeof (dbTmpPrefixName));
            memset (tblTmpPrefixName, 0, sizeof (tblTmpPrefixName));
            memset (columnName, 0, sizeof (columnName));
            
            gsp_objectname *column = (gsp_objectname *)gsp_list_celldata(cell);
            tmpGspNodeText = gsp_node_text((gsp_node*)column);
            _LKT_SQLPARSER_SplitIdentify(tmpGspNodeText, 
                                     tblTmpPrefixName, tblTmpPrefixName, columnName, IDENTIFY_COLUMN);
            columnList[i] = (char*) malloc (COLUMN_NAME_MAX_LEN);
            gsp_free(tmpGspNodeText);
            if (NULL == columnList[i])
            {
                ret = ERR_COMMON_NO_MEM;
                break;
            }
            snprintf (columnList[i], COLUMN_NAME_MAX_LEN, "%s", columnName);
            i++;
        }
        
        if (ERR_COMMON_SUCCESS != ret)
        {
            for (i = 0; i < sqlStmt->columnList->length; i++)
            {
                if(NULL != columnList[i])
                {
                    free (columnList[i]);
                }
            }
            return;
        }
    }


    /* 获取value组，insert支持同时插入多行 */
    gsp_listcell *element = NULL;
    if(sqlStmt->multiTargetList!=NULL && sqlStmt->multiTargetList->length>0)
    {
        /* 获取每个value组 */
        foreach(cell, sqlStmt->multiTargetList)
        {
            gsp_multiTarget *targetValue = (gsp_multiTarget *)gsp_list_celldata(cell);
            if (NULL == targetValue->resultColumnList)
            {
                continue;
            }

            int j = 0;
            
            /* 分解组内的每个value */
            foreach(element, targetValue->resultColumnList)
            {
                gsp_resultColumn *value = (gsp_resultColumn *)gsp_list_celldata(element);

                if ((NULL != value) && 
                    (CHECK_STRING_VALUE (value->expr) || 
                     (CHECK_SIMPLEOBJECT_VALUE(value->expr))))
                {
                    char *myvalue = gsp_node_text((gsp_node*)value);
                    char *mycolumn = columnList[j];
                    char *mytable = tableName;
                    char *mydb = dbPrefixName;  /* 以sqlStmt->targetTableNode的prefixName为主 */
                    
                    int offset = ((gsp_node*)value)->fragment.startToken->nColumn;
                    int len = strlen(myvalue);
                    int idx = j;

                    if (1 == _LKT_IsStringValue (myvalue))
                    {
                        (void) _LKT_SQLPARSER_AddNode (myvalue, mycolumn, mytable, mydb, 
                                                        NULL, offset, len, idx);

                    }

                    gsp_free(myvalue);
                }
                j++;
            }
        }
    }

    /* insert into ... set ...语法 */
    if (NULL != sqlStmt->insertRest)
    {
        TABLE_IDENTIFY_S tableIdentify;
        memset (&tableIdentify, 0, sizeof (tableIdentify));

        if ((NULL != sqlStmt->insertRest->updateTargetList) && 
            (sqlStmt->insertRest->updateTargetList->length > 0))
        {
            foreach(cell, sqlStmt->insertRest->updateTargetList)
            {
                gsp_resultColumn *field = (gsp_resultColumn *)gsp_list_celldata(cell);
                if(field->expr!=NULL && field->expr->leftOperand!=NULL && field->expr->rightOperand!=NULL )
                {
                    if (CHECK_STRING_VALUE(field->expr->rightOperand) || 
                        CHECK_SIMPLEOBJECT_VALUE(field->expr->rightOperand))
                    {
                        char *myvalue  = gsp_node_text((gsp_node*)field->expr->rightOperand);
                        char *identify = gsp_node_text((gsp_node*)field->expr->leftOperand);
                        char *mycolumn = NULL;
                        char *mytable  = NULL;
                        char *mydb     = NULL;
                        int offset = ((gsp_node*)field->expr->rightOperand)->fragment.startToken->nColumn;
                        int len = strlen(myvalue);
                        int idx = -1;

                        _LKT_SQLPARSER_SplitIdentify(identify, dbPrefixName, tblPrefixName, columnName, IDENTIFY_COLUMN);
                        _LKT_SQLPARSER_AssociateNode(&mytable, &mydb, tblPrefixName, dbPrefixName, &tableIdentify);

                        mycolumn = columnName;


                        if (1 == _LKT_IsStringValue (myvalue))
                        {
                            (void) _LKT_SQLPARSER_AddNode (myvalue, mycolumn, mytable, mydb, 
                                                            &tableIdentify, offset, len, idx);
                        }

                        gsp_free(myvalue);
                        gsp_free(identify);
                    }
                }
            }

        }
    }

    if (NULL != sqlStmt->columnList)
    {
        for (i = 0; i < sqlStmt->columnList->length; i++)
        {
            free (columnList[i]);
        }
    }

    if(NULL != sqlStmt->subQueryNode)
    {
        _LKT_SQLPARSER_SelectStmtInfo((gsp_selectStatement*)sqlStmt->subQueryNode);
    }
    
    return;
}

static void _LKT_SQLPARSER_AnalyzeInsert( gsp_insertStatement * psql ) 
{
    _LKT_SQLPARSER_InsertStmtInfo(psql);
    
    return;
}

static void _LKT_SQLPARSER_UpdateStmtInfo( gsp_updateStatement * sqlStmt ) 
{
    char *tmpGspNodeText = NULL;
    TABLE_IDENTIFY_S tableIdentify;
    memset (&tableIdentify, 0, sizeof (tableIdentify));
    int tableNum = 0;
    
    gsp_listcell *cell = NULL;
    char *mytable = NULL;
    if(NULL != sqlStmt->targetTableList)
    {
        foreach(cell, sqlStmt->targetTableList)
        {
            gsp_fromTable *table = (gsp_fromTable*) gsp_list_celldata(cell);
            
            if(NULL != table->tableName)
            {
                tmpGspNodeText = gsp_node_text((gsp_node*)table->tableName);
                _LKT_SQLPARSER_SplitIdentify (tmpGspNodeText, 
                                              tableIdentify.tableNode[tableNum].dbName,
                                              tableIdentify.tableNode[tableNum].tableName,
                                              NULL,
                                              IDENTIFY_TABLE); 
                gsp_free(tmpGspNodeText);
            }
            if (NULL != table->aliasClause)
            {
                tmpGspNodeText = gsp_node_text((gsp_node*)table->aliasClause);
                snprintf (tableIdentify.tableNode[tableNum].tableAlias, 
                          TABLE_ALIAS_NAME_MAX_LEN, 
                          "%s", 
                          tmpGspNodeText);
                gsp_free(tmpGspNodeText);
            }
            tableNum++;
        }
        tableIdentify.tableNum = tableNum;
    }
    
    char dbPrefixName[DATABASE_NAME_MAX_LEN]     = {0};
    char tblPrefixName[TABLE_NAME_MAX_LEN]    = {0};
    char columnName[COLUMN_NAME_MAX_LEN] = {0};

    if(sqlStmt->resultColumnList!=NULL && sqlStmt->resultColumnList->length>0)
    {
        foreach(cell, sqlStmt->resultColumnList)
        {
            gsp_resultColumn *field = (gsp_resultColumn *)gsp_list_celldata(cell);
            if(field->expr!=NULL && field->expr->leftOperand!=NULL && field->expr->rightOperand!=NULL )
            {
                if ((CHECK_STRING_VALUE(field->expr->rightOperand)) ||
                    (CHECK_SIMPLEOBJECT_VALUE(field->expr->rightOperand)))

                {
                    char *myvalue  = gsp_node_text((gsp_node*)field->expr->rightOperand);
                    char *identify = gsp_node_text((gsp_node*)field->expr->leftOperand);
                    char *mycolumn = NULL;
                    char *mytable  = NULL;
                    char *mydb     = NULL;
                    int offset = ((gsp_node*)field->expr->rightOperand)->fragment.startToken->nColumn;
                    int len = strlen(myvalue);
                    int idx = -1;

                    _LKT_SQLPARSER_SplitIdentify(identify, dbPrefixName, tblPrefixName, columnName, IDENTIFY_COLUMN);
                    _LKT_SQLPARSER_AssociateNode(&mytable, &mydb, tblPrefixName, dbPrefixName, &tableIdentify);

                    mycolumn = columnName;

                    if (1 == _LKT_IsStringValue (myvalue))
                    {
                        (void) _LKT_SQLPARSER_AddNode (myvalue, mycolumn, mytable, mydb, 
                                                        &tableIdentify, offset, len, idx);

                    }

                    gsp_free(myvalue);
                    gsp_free(identify);
                }
            }
        }
    }

    if(NULL != sqlStmt->whereCondition)
    {
        _LKT_SQLPARSER_ParseWhereCondition(sqlStmt->whereCondition->condition,  &tableIdentify);
    }
    
    return;
}

static void _LKT_SQLPARSER_AnalyzeUpdate( gsp_updateStatement * psql ) 
{
    _LKT_SQLPARSER_UpdateStmtInfo(psql);
    
    return;
}

static void _LKT_SQLPARSER_Analyzestmt( gsp_sql_statement * sqlStmt ) 
{
    if (NULL == sqlStmt)
    {
        return;
    }
    
    if ((sqlStmt->stmt == NULL && sqlStmt->parseTree == NULL))
    {
        return;
    }
    
    gsp_node* node = (gsp_node*)sqlStmt->stmt;
    if(node == NULL)
    {
        node = sqlStmt->parseTree;
    }

    /* 添加SQL语句 */
    char *originSql = NULL;
    originSql = _LKT_SQLPARSER_AddOriginSQL (gsql);
    if (NULL == originSql)
    {
        return;
    }
    
    _LKT_SQLPARSER_AddOStatementType (sqlStmt->stmtType);

    /* 分析SQL语句 */
    switch(sqlStmt->stmtType)
    {
        case sstselect:
        {
            _LKT_SQLPARSER_AnalyzeSelect((gsp_selectStatement *)node);
            break;
        }
        case sstdelete:
        {
            _LKT_SQLPARSER_AnalyzeDelete((gsp_deleteStatement *)node);
            break;
        }
        case sstinsert:
        {
            _LKT_SQLPARSER_AnalyzeInsert((gsp_insertStatement *)node);
            break;
        }
        case sstupdate:
        {
            _LKT_SQLPARSER_AnalyzeUpdate((gsp_updateStatement *)node);
            break;
        }
        default:
        {
            break;
        }
    }

    return;
}

void LKT_SQLPARSER_Release (SQLPARSER_S *sqlparser)
{
    if (NULL == sqlparser)
    {
        return;
    }

    int i = 0;
    for (i = 0; i < sqlparser->statementnum; i++)
    {
        _LKT_FREE_Statement (sqlparser->statement[i]);
        sqlparser->statement[i] = NULL;
    }

    return;
}

int LKT_SQLPARSER_ParseSQL(int dbverdor,  const char *sqlquery, SQLPARSER_S *sqlpasrer, logger func)
{
    (void) dbverdor;
    gsql = sqlquery;

    int ret = ERR_COMMON_SUCCESS;
    
    if ((NULL == sqlquery) || (NULL == sqlpasrer))
    {
        ret = ERR_COMMON_INVALID_PARAM;
        _LKT_PRINT_LOG (ret, "invalid param");
        return ret;
    }
    
    SQLPARSER_WORKER_S *worker = _LKT_SQLPARSER_GetParserWorker();
    memset (worker, 0, sizeof (SQLPARSER_WORKER_S));
    worker->logFunc = func;
    
    /* 创建SQL解析器 */
    gsp_sqlparser *gspparser = NULL;
    ret = gsp_parser_create(dbvmysql,&gspparser);
    if (ERR_COMMON_SUCCESS != ret)
    {
        ret = ERR_SQLPARSER_FAILED;
        _LKT_PRINT_LOG (ret, gsp_errmsg(gspparser));
        return ret;
    }

    do 
    {
        ret = gsp_check_syntax(gspparser, (char*)sqlquery);
        if (ERR_COMMON_SUCCESS != ret)
        {
            ret = ERR_SQLPARSER_FAILED;
            _LKT_PRINT_LOG (ret, gsp_errmsg(gspparser));
            break;
        }

        if (sqlpasrer->statementnum > 1)
        {
            ret = ERR_SQLPARSER_FAILED;
            _LKT_PRINT_LOG (ret, "sqlparser can not parse more than 1 statement\n");
            break;
        }
        
        /* 正常情况下, sqlpasrer内存由外部调用者释放 */
        int i = 0;
        sqlpasrer->statementnum = gspparser->nStatement;
        for (i = 0; i < sqlpasrer->statementnum; i++)
        {
            sqlpasrer->statement[i] = (SQLPARSER_STATEMENT_S*) malloc (sizeof (SQLPARSER_STATEMENT_S));
            if (NULL == sqlpasrer->statement[i])
            {
                ret = ERR_COMMON_NO_MEM;
                _LKT_PRINT_LOG (ret, "no memory");
                break;
            }
            memset (sqlpasrer->statement[i], 0, sizeof (SQLPARSER_STATEMENT_S));
        }
        
        if (ERR_COMMON_SUCCESS != ret)
        {
            break;
        }

        /* 解析SQL语句 */
        int j = 0;
        gsp_sql_statement *stmt = NULL;
        for(j = 0; j < gspparser->nStatement; j++)
        {
            worker->parseStatement = sqlpasrer->statement[j];
            
            stmt = &gspparser->pStatement[j];
            
            _LKT_SQLPARSER_Analyzestmt(stmt);
        }
    } while (0);

    gsp_parser_free(gspparser);
    
    /* 释放解析器 */
    if (ERR_COMMON_SUCCESS != ret)
    {
        LKT_SQLPARSER_Release (sqlpasrer);
        
        _LKT_PRINT_LOG (ret, "parser failed");
    }
    
    return ret;
}

